#include "CaptureVideoStream.h"
#include "CaptureDevice.h"

BEGIN_DIRECTSHOWWRAPPER_NAMESPACE

CaptureVideoStream::CaptureVideoStream(CaptureDevice *pCaptureDevice) :
    m_pCaptureDevice(pCaptureDevice)
{
    if(!Initialize())
    {
        throw new _com_error(E_FAIL);
    }
}

CaptureVideoStream::~CaptureVideoStream()
{
    if(m_pCaptureDevice != NULL)
    {
        delete m_pCaptureDevice;
        m_pCaptureDevice = NULL;
    }

	if(m_pSampleGrabber != NULL)
    {
        m_pSampleGrabber->Release();
		m_pSampleGrabber.Detach();
    }


    if(m_pMediaCtrl == NULL)
	{
		m_pMediaCtrl->Release();
		m_pMediaCtrl.Detach();
	}

	if(m_pMediaEvent == NULL)
	{
		m_pMediaEvent->Release();
		m_pMediaEvent.Detach();
	}

    if(m_pVideoWindow == NULL)
	{
		m_pVideoWindow->Release();
		m_pVideoWindow.Detach();
	}

	if(m_pCaptureGraphBuilder2Ptr == NULL)
	{
		m_pCaptureGraphBuilder2Ptr->Release();
		m_pCaptureGraphBuilder2Ptr.Detach();
	}

	if(m_pGraphBuilderPtr == NULL)
	{
		m_pGraphBuilderPtr->Release();
		m_pGraphBuilderPtr.Detach();
	}
}

STDMETHODIMP_(ULONG) CaptureVideoStream::AddRef()
{
	InterlockedIncrement(&m_Ref);
	return m_Ref;
}

STDMETHODIMP CaptureVideoStream::BufferCB(double dblSampleTime, BYTE * pBuffer, long lBufferSize)
{
    return 0;
}

bool CaptureVideoStream::Initialize()
{
    HRESULT hr;

	hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, 
						  NULL,
						  CLSCTX_INPROC_SERVER,
						  IID_ICaptureGraphBuilder2, 
						 (void **)&m_pCaptureGraphBuilder2Ptr); 
	if(SUCCEEDED(hr))
	{
		hr = CoCreateInstance(CLSID_FilterGraph, 
							  NULL,
							  CLSCTX_INPROC_SERVER,
							  IID_IGraphBuilder, 
							 (void **)&m_pGraphBuilderPtr); 
		if(SUCCEEDED(hr))
		{
			hr = m_pGraphBuilderPtr->QueryInterface(
					IID_IMediaControl, (void **)&m_pMediaCtrl);

			hr = m_pGraphBuilderPtr->QueryInterface(
					IID_IMediaEvent, (void **)&m_pMediaEvent);

            hr = m_pGraphBuilderPtr->QueryInterface(
					IID_IVideoWindow, (void **)&m_pVideoWindow);

			hr = m_pCaptureGraphBuilder2Ptr->SetFiltergraph(m_pGraphBuilderPtr);

            IBaseFilterPtr pDeviceFilter = m_pCaptureDevice->BindDeviceFilter();
	        if(pDeviceFilter != NULL)
	        {
		        HRESULT hr;
		        hr = m_pGraphBuilderPtr->AddFilter(
                    pDeviceFilter, m_pCaptureDevice->GetName());

                // Create a samplel grabber.
                IBaseFilter *pBaseFilter = NULL;
                hr = CoCreateInstance(CLSID_SampleGrabber, 
				    				  NULL, 
					    			  CLSCTX_INPROC,
						    		  IID_IBaseFilter, 
							    	 (void**)&pBaseFilter);
				m_pSampleGrabber = pBaseFilter;

                hr = m_pGraphBuilderPtr->AddFilter(
                    (IBaseFilterPtr)m_pSampleGrabber, L"SampleGrabber");
	
				
				hr = m_pSampleGrabber->SetBufferSamples(FALSE);
				hr = m_pSampleGrabber->SetOneShot(FALSE);
				hr = m_pSampleGrabber->SetCallback((ISampleGrabberCB *)this, 1);
                
				pBaseFilter->Release();
	        }	

            return true;
		}
	}

    return false;
}

STDMETHODIMP CaptureVideoStream::QueryInterface(REFIID riid, void ** ppv)
{
	if(riid == IID_ISampleGrabberCB || riid == IID_IUnknown) 
	{
		*ppv = (void *)static_cast<ISampleGrabberCB *>(this);
		AddRef();
        return S_OK;
	}    

    return E_NOINTERFACE;
}

STDMETHODIMP_(ULONG) CaptureVideoStream::Release()
{
	InterlockedDecrement(&m_Ref);
	return m_Ref;
}

STDMETHODIMP CaptureVideoStream::SampleCB(double SampleTime, IMediaSample * pSample)
{
    return 0;
}

void CaptureVideoStream::Start()
{
	HRESULT hr;
	hr = m_pCaptureGraphBuilder2Ptr->RenderStream(&PIN_CATEGORY_CAPTURE, 
											 &MEDIATYPE_Video,
											 m_pCaptureDevice->BindDeviceFilter(),
											 NULL,
											 NULL);
    // Prevent the ActiveMovie window shown.
    hr = m_pVideoWindow->put_AutoShow(OAFALSE);

    hr = m_pMediaCtrl->Run();
}

END_DIRECTSHOWWRAPPER_NAMESPACE